﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Giant.Core;
using Giant.Core.Domain.Users;
using Giant.Core.Domain.Messages;
using Giant.Core.Domain.News;
using Giant.Core.Domain.Sites;
using Giant.Services.Common;
using Giant.Services.Users;
using Giant.Services.Events;
using Giant.Services.Helpers;
using Giant.Services.Localization;
using Giant.Services.Media;
using Giant.Services.Seo;
using Giant.Services.Sites;
using Giant.Core.Domain;
using Giant.Core.Domain.Blogs;

namespace Giant.Services.Messages
{
    public partial class MessageTokenProvider : IMessageTokenProvider
    {
        #region Fields

        private readonly ILanguageService _languageService;
        private readonly ILocalizationService _localizationService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly IWorkContext _workContext;
        private readonly ISiteService _siteService;
        private readonly ISiteContext _siteContext;
        private readonly MessageTemplatesSettings _templatesSettings;
        private readonly IEventPublisher _eventPublisher;
        private readonly SiteInformationSettings _siteInformationSettings;

        #endregion

        #region Ctor

        public MessageTokenProvider(ILanguageService languageService,
            ILocalizationService localizationService, 
            IDateTimeHelper dateTimeHelper,
            IWorkContext workContext,
            ISiteService siteService,
            ISiteContext siteContext,
            MessageTemplatesSettings templatesSettings,
            IEventPublisher eventPublisher,
            SiteInformationSettings siteInformationSettings)
        {
            this._languageService = languageService;
            this._localizationService = localizationService;
            this._dateTimeHelper = dateTimeHelper;
            this._workContext = workContext;
            this._siteService = siteService;
            this._siteContext = siteContext;
            this._templatesSettings = templatesSettings;
            this._eventPublisher = eventPublisher;
            this._siteInformationSettings = siteInformationSettings;
        }

        #endregion

        #region Utilities

        /// <summary>
        /// Get site URL
        /// </summary>
        /// <param name="siteId">Site identifier; Pass 0 to load URL of the current site</param>
        /// <param name="useSsl">Use SSL</param>
        /// <returns></returns>
        protected virtual string GetSiteUrl(int siteId = 0, bool useSsl = false)
        {
            var site = _siteService.GetSiteById(siteId) ?? _siteContext.CurrentSite;

            if (site == null)
                throw new Exception("No site could be loaded");

            return useSsl ? site.SecureUrl : site.Url;
        }

        #endregion

        #region Methods

        public virtual void AddSiteTokens(IList<Token> tokens, Site site, EmailAccount emailAccount)
        {
            if (emailAccount == null)
                throw new ArgumentNullException("emailAccount");

            tokens.Add(new Token("Site.Name", site.GetLocalized(x => x.Name)));
            tokens.Add(new Token("Site.URL", site.Url, true));
            tokens.Add(new Token("Site.Email", emailAccount.Email));
            tokens.Add(new Token("Site.CompanyName", site.CompanyName));
            tokens.Add(new Token("Site.CompanyAddress", site.CompanyAddress));
            tokens.Add(new Token("Site.CompanyPhoneNumber", site.CompanyPhoneNumber));

            //event notification
            _eventPublisher.EntityTokensAdded(site, tokens);
        }

        public virtual void AddUserTokens(IList<Token> tokens, User user)
        {
            tokens.Add(new Token("User.Email", user.Email));
            tokens.Add(new Token("User.Username", user.Username));
            tokens.Add(new Token("User.FullName", user.GetFullName()));
            tokens.Add(new Token("User.FirstName", user.GetAttribute<string>(SystemUserAttributeNames.FirstName)));
            tokens.Add(new Token("User.LastName", user.GetAttribute<string>(SystemUserAttributeNames.LastName)));

            //note: we do not use SEO friendly URLS because we can get errors caused by having .(dot) in the URL (from the email address)
            //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs)
            string passwordRecoveryUrl = string.Format("{0}passwordrecovery/confirm?token={1}&email={2}", GetSiteUrl(), user.GetAttribute<string>(SystemUserAttributeNames.PasswordRecoveryToken), HttpUtility.UrlEncode(user.Email));
            string accountActivationUrl = string.Format("{0}user/activation?token={1}&email={2}", GetSiteUrl(), user.GetAttribute<string>(SystemUserAttributeNames.AccountActivationToken), HttpUtility.UrlEncode(user.Email));
            tokens.Add(new Token("User.PasswordRecoveryURL", passwordRecoveryUrl, true));
            tokens.Add(new Token("User.AccountActivationURL", accountActivationUrl, true));

            //event notification
            _eventPublisher.EntityTokensAdded(user, tokens);
        }

        public virtual void AddNewsLetterSubscriptionTokens(IList<Token> tokens, NewsLetterSubscription subscription)
        {
            tokens.Add(new Token("NewsLetterSubscription.Email", subscription.Email));


            const string urlFormat = "{0}newsletter/subscriptionactivation/{1}/{2}";

            var activationUrl = String.Format(urlFormat, GetSiteUrl(), subscription.NewsLetterSubscriptionGuid, "true");
            tokens.Add(new Token("NewsLetterSubscription.ActivationUrl", activationUrl, true));

            var deActivationUrl = String.Format(urlFormat, GetSiteUrl(), subscription.NewsLetterSubscriptionGuid, "false");
            tokens.Add(new Token("NewsLetterSubscription.DeactivationUrl", deActivationUrl, true));

            //event notification
            _eventPublisher.EntityTokensAdded(subscription, tokens);
        }

        public virtual void AddBlogCommentTokens(IList<Token> tokens, BlogComment blogComment)
        {
            tokens.Add(new Token("BlogComment.BlogPostTitle", blogComment.BlogPost.Title));

            //event notification
            _eventPublisher.EntityTokensAdded(blogComment, tokens);
        }

        public virtual void AddNewsCommentTokens(IList<Token> tokens, NewsComment newsComment)
        {
            tokens.Add(new Token("NewsComment.NewsTitle", newsComment.NewsItem.Title));

            //event notification
            _eventPublisher.EntityTokensAdded(newsComment, tokens);
        }
        

        public virtual string[] GetListOfAllowedTokens()
        {
            var additionTokens = new AdditionTokensAddedEvent();
            _eventPublisher.Publish(additionTokens);

            var allowedTokens = new List<string>
            {
                "%Site.Name%",
                "%Site.URL%",
                "%Site.Email%",
                "%Site.CompanyName%",
                "%Site.CompanyAddress%",
                "%Site.CompanyPhoneNumber%",
                "%Order.UserFullName%",
                "%Order.UserEmail%",
                "%User.Email%", 
                "%User.Username%",
                "%User.FullName%",
                "%User.FirstName%",
                "%User.LastName%",
                "%User.PasswordRecoveryURL%", 
                "%User.AccountActivationURL%", 
                "%NewsLetterSubscription.Email%", 
                "%NewsLetterSubscription.ActivationUrl%",
                "%NewsLetterSubscription.DeactivationUrl%", 
                "%NewsComment.NewsTitle%",           
                "%Facebook.URL%",
                "%Twitter.URL%",
                "%YouTube.URL%",
                "%GooglePlus.URL%"
            };
            allowedTokens.AddRange(additionTokens.AdditionTokens);

            return allowedTokens.Distinct().ToArray();
        }

        #endregion
    }
}
